#include "MTorus.h"


MTorus::MTorus(float ar1, float ar2, int ars, int avs, float aox, float aoy,float aoz)
{
	name = "Torus";
	verts = NULL;
	normal = NULL;
	bNormal = false;
	updateTorus(ar1,ar2,ars,avs,aox,aoy,aoz);
}


MTorus::~MTorus(void)
{
	if(verts) {
		for(int i = 0; i<rs; i++) {
			delete []verts[i];
		}
		delete []verts;
	}
	if(normal) {
		for(int i = 0; i<rs; i++) {
			delete normal[i];
		}
		delete []normal;
	}
}

MTorus *MTorus::makeTorus(float ar1, float ar2, int ars, int avs, float aox, float aoy,float aoz) {
	if(ar1<=0 || ar2==0 || ar1<ar2 || ars < 3 || avs < 3) {//at least 1 radial stacks and 4 vertical slice
		return NULL;
	}
	return new MTorus(ar1,ar2,ars,avs,aox,aoy,aoz);
}

void MTorus::drawShape() {

}

void MTorus::drawTorus(void(*func)(const MVertex &p1,  const MVertex &p2, const MVertex &p3, int ic),
	void(*drawline)(const MVertex &p1,  const MVertex &p2,int ic)) {
	static const int icolor = 5;
	if(!func) {	//return function
		return;
	}
	int i,j;
	for(i = 0; i<rs; i++) {
		int nextr = ((i==(rs-1))?0:i+1);
		for(j=0; j<vs; j++) {
			int nextc = ((j==(vs-1))?0:j+1);
			func(verts[i][j],verts[nextr][nextc],verts[nextr][j],icolor);
			func(verts[i][j],verts[i][nextc],verts[nextr][nextc],icolor);
		}
	}
	if(bNormal && drawline) {
		for(i=0; i<rs; i++) {
			for(j=0; j<vs; j++) {
				drawline(verts[i][j],verts[i][j]+normal[i][j]*NORMALEN,1);
			}
		}
	}
	if(step < rs) {
		step++;
	}
}

void MTorus::updateTorus(float ar1, float ar2, int ars, int avs, float aox, float aoy,float aoz) {
	if(ar1<=0 || ar2==0 || ar1<ar2 || ars < 3 || avs < 3) {//at least 1 radial stacks and 4 vertical slice
		return;
	}
	//delete old array
	if(verts) {
		for(int i = 0; i<rs; i++) {
			delete []verts[i];
		}
		delete []verts;
	}
	if(normal) {
		for(int i = 0; i<rs; i++) {
			delete normal[i];
		}
		delete []normal;
	}
	ox = aox;
	oy = aoy;
	oz = aoz;
	r1 = ar1;
	r2 = ar2;
	rs = ars;
	vs = avs;
	step = 1;
	//create array
	verts = new MVertex*[rs];
	normal = new MVertex*[rs];
	int i, j;
	for(i = 0; i<rs; i++) {
		verts[i] = new MVertex[vs];
		normal[i] = new MVertex[vs];
	}

	//populate vertexpoint
	MVertex p1(0,r2,0);
	for(j=0; j<vs; j++) {
		verts[0][j] = p1.rotateZ(2*PI/vs*(j)).translate(r1,0,0);
	}

	for(i = 1; i<rs; i++) {
		float theta = 2*PI/rs;
		for(j=0; j<vs; j++) {
			verts[i][j] = verts[i-1][j].rotateY(theta);
		}
	}

	for(i=0; i<rs; i++) {
		for(j=0; j<vs; j++) {
			MVertex top = (i==0?verts[rs-1][j]:verts[i-1][j]);
			MVertex bottom = (i==(rs-1)?verts[0][j]:verts[i+1][j]);
			MVertex left = (j==0?verts[i][vs-1]:verts[i][j-1]);
			MVertex right = (j==(vs-1)?verts[i][0]:verts[i][j+1]);
			calculateNormal(&normal[i][j],verts[i][j],top,bottom,left,right);
		}
	}

}

bool MTorus::isComplete() const {
	return step == rs;
}

void MTorus::resetStep() {
	step = 1;
}

void MTorus::incrementSlice() {
	if(vs < 50) {
		this->updateTorus(r1,r2,rs,vs+1,ox,oy,oz);
	}
}

void MTorus::decrementSlice() {
	if(vs > 3) {
		this->updateTorus(r1,r2,rs,vs-1,ox,oy,oz);
	}
}

void MTorus::incrementStack() {
	if(rs < 50) {
		this->updateTorus(r1,r2,rs+1,vs,ox,oy,oz);
	}
}

void MTorus::decrementStack() {
	if(rs > 3) {
		this->updateTorus(r1,r2,rs-1,vs,ox,oy,oz);
	}
}